import { GameConfig } from '../configs/GameConfig';
import { AdsUtil } from '../etc/AdsUtil';
import { Attribute } from '../etc/Attribute';
import { Constants } from '../etc/Constants';
import { updater } from '../etc/Updater';
import { util } from '../etc/Util';
import Appearance from '../model/Appearance';
import { AskAdsWindow } from '../ui/AskAdsWindow';
import { AutoAdsWindow } from '../ui/AutoAdsWindow';
import { Notice } from '../ui/Notice';
import { GameplayModuleData } from './GameplayModule';
import { EnumBagItemGrid, ItemModuleData } from './ItemModule';

export class PlayerModuleData extends Subdata {
    @Decorator.persistence()
    reserveAttribute: Attribute.AttributeArray;
    
    get dataName(): string { return 'PlayerModuleData' }
    
    protected initDefaultData() {
        this.reserveAttribute = {};
        this.reserveAttribute[Attribute.EnumAttributeType.power] = 5000;
        this.save(true);
    }
}

export const PlayAutoAdsRewardCount = 2000

export class PlayerModuleC extends ModuleC<PlayerModuleS, PlayerModuleData>{
    // 属性变更事件
    onAttributeChanged:Action = new Action()

    // 即时属性存根(用于记录属性变更)
    private playerStashedAttrBuffer = {};
    // 即时属性容器
    private attribute: Attribute.AttributeValueObject = new Attribute.AttributeValueObject();

    protected onStart() {
        this.data.onDataChange.add(this.onPlayerAttributeDataChanged, this);
        this.syncPlayerStashedAttribute();

        let adsRewardTrigger = <Trigger>GameObject.findGameObjectById('014A6C38')
        adsRewardTrigger.onEnter.add(this.onEnterAdsArea.bind(this))
    }

    protected onUpdate(): void {
        
    }

    // 自动播放广告(三分钟)
    @updater.updateByFrameInterval(30 * 60 * 3)
    autoPushAdsWindow(){
        UIService.show(AutoAdsWindow)
    }

    // 进入广告触发器
    onEnterAdsArea(other:GameObject){
        if(!util.isSelfPlayer(other)) return
        
        let window = UIService.show(AskAdsWindow)
        window.setInfo(
            ()=>{
                AdsUtil.playRewardAds(
                    // 广告播放成功, 原地复活
                    ()=>{
                        this.server.net_play_auto_ads_success(Constants.NormalAdsRewardCount)
                    },
                    // 广告播放失败
                    ()=>{ 
                        Notice.showTopNotice('广告未完全播放完成, 无法获得奖励哦~')
                    }
                )
            },
            this
        )
    }

    // 获取玩家属性
    getAttr(type: Attribute.EnumAttributeType): number {
        if (!Attribute.IsStashAttribute(type)) return this.attribute.getValue(type)
        return this.data.reserveAttribute[type] || 0;
    }
    
    // 比对变更属性
    private onPlayerAttributeDataChanged() {
        this.syncPlayerStashedAttribute();
        this.onAttributeChanged.call()
    }

    // 同步玩家数据到缓存数据
    private syncPlayerStashedAttribute() {
        Object.assign(this.playerStashedAttrBuffer, this.data.reserveAttribute);
    }

    // 服务器发送的请求玩家233名称
    net_get_nick_name() {
        let name = AccountService.getNickName()
        if(SystemUtil.isPIE){
            name = `本地玩家韩书然咯咯咯${this.localPlayerId}`
        }
        this.server.net_nick_name(name)
    }
    
    // 当自动播放广告成功
    playAutoAdsSuccess() {
        this.server.net_play_auto_ads_success(Constants.AutoPushAdsRewardCount)
    }

    // 服务器发送的初始化属性列表
    net_init_attr(attributeArray: Attribute.AttributeArray) {
        for (let type in attributeArray) {
            let val = attributeArray[type];
            let typeKey = Number(type)
            this.attribute.setAttribute(typeKey, val);
            if(SystemUtil.isPIE){
                console.log(`属性:${typeKey}:${val}`);
            }
        }
        this.onAttributeChanged.call()
    }
    
    // 服务器发送的属性变更
    net_change_attr(type: Attribute.EnumAttributeType, value: number) {
        this.attribute.setAttribute(type, value);
        this.onAttributeChanged.call()
    }
}

export class PlayerModuleS extends ModuleS<PlayerModuleC, PlayerModuleData>{
    private appearanceMapping: Map<number, Appearance> = new Map()
    private playerAttributeMap: Map<number, Attribute.AttributeValueObject> = new Map();

    protected onPlayerEnterGame(player: mw.Player) {
        // 空名字
        player.character.asyncReady().then(character => { character.displayName = " " })
        // 初始化玩家信息脚本
        this.initPlayerAppearanceScript(player)
        // 初始化玩家属性
        this.recalculateAttribute(player.playerId)
    }

    protected onPlayerLeft(player: mw.Player): void {
        // 外观
        if (this.appearanceMapping.has(player.playerId)) {
            let appearance = this.appearanceMapping.get(player.playerId)
            appearance.destroy()
            this.appearanceMapping.delete(player.playerId)
        }
        // 属性
        this.playerAttributeMap.delete(player.playerId);
    }

    net_test_add() {
        this.addPlayerAttr(this.currentPlayerId, Attribute.EnumAttributeType.money, 20)
        this.addPlayerAttr(this.currentPlayerId, Attribute.EnumAttributeType.power, 200)
    }
    
    net_play_auto_ads_success(count:number) {
        this.addPlayerAttr(this.currentPlayerId, Attribute.EnumAttributeType.power, count)
    }
    
    reducePlayerAttr(playerID: number, type: Attribute.EnumAttributeType, value: number) {
        if (!Player.getPlayer(playerID)) return //已下线
        if (Attribute.IsStashAttribute(type)) {
            this.reducePlayerAttrStash(playerID, type, value);
            return
        }
        this.reducePlayerAttrIT(playerID, type, value);
    }

    addPlayerAttr(playerID: number, type: Attribute.EnumAttributeType, value: number) {
        if (!Player.getPlayer(playerID)) return //已下线
        if (Attribute.IsStashAttribute(type)) {
            this.addPlayerAttrStash(playerID, type, value);
            return
        }
        this.addPlayerAttrIT(playerID, type, value);
    }
    
    getPlayerAttr(playerID: number, type: Attribute.EnumAttributeType): number {
        if (!Player.getPlayer(playerID)) return 0 //已下线
        // 是否为存储属性
        if (Attribute.IsStashAttribute(type)) {
            return this.getPlayerData(playerID).reserveAttribute[type] || 0;
        }
        return this.playerAttributeMap.get(playerID).getValue(type);
    }
    
    // 减少玩家储存属性(不随游戏结束清空的属性)
    private reducePlayerAttrStash(playerID: number, type: Attribute.EnumAttributeType, value: number) {
        let data = this.getPlayerData(playerID);
        if(!data.reserveAttribute[type]) return
        
        data.reserveAttribute[type] = data.reserveAttribute[type] - value;
        data.save(true);
    }

    // 增加玩家储存属性(不随游戏结束清空的属性)
    private addPlayerAttrStash(playerID: number, type: Attribute.EnumAttributeType, value: number) {
        let data = this.getPlayerData(playerID);
        
        if(!data.reserveAttribute[type]) data.reserveAttribute[type] = 0
        data.reserveAttribute[type] += value;
        data.save(true);
    }

    // 减少玩家即时属性
    private reducePlayerAttrIT(playerID: number, type: Attribute.EnumAttributeType, value: number) {
        let vo = this.playerAttributeMap.get(playerID);
        vo.reduceValue(type, value);
        this.syncChangePlayerAttr(playerID, type);
    }

    // 增加玩家即时属性
    private addPlayerAttrIT(playerID: number, type: Attribute.EnumAttributeType, value: number) {
        let vo = this.playerAttributeMap.get(playerID);
        vo.addValue(type, value);
        this.syncChangePlayerAttr(playerID, type);
    }
    
    // 同步属性变更(单一)
    private syncChangePlayerAttr(playerID: number, type: Attribute.EnumAttributeType) {
        let attrVo = this.playerAttributeMap.get(playerID);
        this.getClient(playerID).net_change_attr(type, attrVo.getValue(type));
    }

    // 初始化玩家外观脚本
    private async initPlayerAppearanceScript(player: Player) {
        let playerID = player.playerId
        if (this.appearanceMapping.has(playerID)) return

        let appearance = await Script.spawnScript(Appearance)
        appearance.init(playerID)
        appearance.playerName = ' ' // 不加这个有问题
        // 赋值玩家最大投掷距离
        let gameMD = DataCenterS.getData(playerID, GameplayModuleData)
        appearance.playerRank = gameMD.maxDistance

        this.appearanceMapping.set(playerID, appearance)

        this.getClient(player.playerId).net_get_nick_name()
    }

    recalculateAttribute(playerID:number){
        let attrVo = this.playerAttributeMap.get(playerID)
        if(!attrVo){
            attrVo = new Attribute.AttributeValueObject()
            this.playerAttributeMap.set(playerID, attrVo)
        }
        attrVo.clear()
        let itemData = DataCenterS.getData(playerID, ItemModuleData)
        for(let grid = EnumBagItemGrid.petStart;grid <= EnumBagItemGrid.petEnd ;grid++){
            let petVo = itemData.getItemByGrid(grid)
            if(!petVo) continue
            let petCfg = GameConfig.Pet.getElement(petVo.baseInfo.cfgID)
            petCfg.AttrType.forEach((type, index)=>{
                let value = petCfg.AttrValue[index]
                attrVo.addValue(type, value)
            })
        }
        // 同步
        this.getClient(playerID).net_init_attr(attrVo.attributeArray);
    }

    net_nick_name(name: string) {
        if(!this.appearanceMapping.has(this.currentPlayerId)) return
        this.appearanceMapping.get(this.currentPlayerId).playerName = name
    }

    net_add_money() {
        this.addPlayerAttr(this.currentPlayerId, Attribute.EnumAttributeType.money, 50)
    }
}